home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 17 / CU Amiga Magazine's Super CD-ROM 17 (1997)(EMAP Images)(GB)[!][issue 1997-12].iso / CUCD / Programming / DiceSource / src / dc1 / genbool.c < prev    next >
C/C++ Source or Header  |  1997-09-09  |  21KB  |  889 lines

  1. /*
  2.  *    (c)Copyright 1992-1997 Obvious Implementations Corp.  Redistribution and
  3.  *    use is allowed under the terms of the DICE-LICENSE FILE,
  4.  *    DICE-LICENSE.TXT.
  5.  */
  6.  
  7. /*
  8.  *  GENBOOL.C    Boolean operators, compare
  9.  *        and logic (!).
  10.  *
  11.  *  You must be careful not to free storage if it will get overwritten
  12.  *  before it is used.
  13.  */
  14.  
  15. /*
  16. **      $Filename: bool.c $
  17. **      $Author: dice $
  18. **      $Revision: 30.156 $
  19. **      $Date: 1995/01/11 05:04:46 $
  20. **      $Log: genbool.c,v $
  21.  * Revision 30.156  1995/01/11  05:04:46  dice
  22.  * added test for void compare against int constant in optimization
  23.  *
  24.  * Revision 30.5  1994/06/13  18:37:29  dice
  25.  * .
  26.  *
  27.  * Revision 30.0  1994/06/10  18:04:51  dice
  28.  * .
  29.  *
  30.  * Revision 1.7  1993/11/15  21:01:43  jtoebes
  31.  * Fixed BUG01143 - Problem with ?: constructs generating an error for void types.
  32.  *
  33.  * Revision 1.6  1993/09/11  22:36:22  jtoebes
  34.  * Fixed BUG06009.
  35.  * Minor cleanup of some duplicated code.
  36.  *
  37.  * Revision 1.5  1993/09/05  23:40:19  jtoebes
  38.  * Fixed BUG06037 - Failure to warn on if test for structure when
  39.  * involved with the ! operation.
  40.  *
  41. **/
  42.  
  43. #include "defs.h"
  44.  
  45. Prototype void BoolLabels(Exp *, long, long);
  46. Prototype void GenCondBranch(Exp **);
  47. Prototype void GenAndAnd(Exp **);
  48. Prototype void GenOrOr(Exp **);
  49. Prototype void GenBoolCompareSame(Exp **);
  50. Prototype void GenBoolCompare(Exp **);
  51. Prototype void GenNot(Exp **);
  52. Prototype void GenColon(Exp **);
  53. Prototype void GenQuestion(Exp **);
  54.  
  55. Local void TerminateCondition(Exp *, Exp *);
  56.  
  57. /*
  58.  *  Basically, if the parent exp node requests a condition branch of the
  59.  *  child it may ask the child to branch on either a false or a true
  60.  *  condition but not both.
  61.  */
  62.  
  63. void
  64. BoolLabels(Exp *exp, long subcond1, long subcond2)
  65. {
  66.     if (exp->ex_Flags & EF_COND) {
  67.     exp->ex_Flags |= EF_CONDACK;
  68.     if (exp->ex_Cond < 0)
  69.         exp->ex_LabelT = AllocLabel();
  70.     else
  71.         exp->ex_LabelF = AllocLabel();
  72.     } else {
  73.     exp->ex_LabelT = AllocLabel();
  74.     exp->ex_LabelF = AllocLabel();
  75.     exp->ex_Cond = 0;
  76.     }
  77.     if (subcond1) {
  78.     Exp *e = exp->ex_ExpL;
  79.  
  80.     e->ex_Flags |= EF_COND;
  81.     e->ex_Cond = subcond1;
  82.     if (subcond1 > 0)
  83.         e->ex_LabelT = exp->ex_LabelT;
  84.     else
  85.         e->ex_LabelF = exp->ex_LabelF;
  86.     }
  87.     if (subcond2) {
  88.     Exp *e = exp->ex_ExpR;
  89.  
  90.     e->ex_Flags |= EF_COND;
  91.     e->ex_Cond = subcond2;
  92.     if (subcond2 > 0)
  93.         e->ex_LabelT = exp->ex_LabelT;
  94.     else
  95.         e->ex_LabelF = exp->ex_LabelF;
  96.     }
  97. }
  98.  
  99. /*
  100.  *  the GenCondBranch() is usually inserted by statement label nodes such
  101.  *  as 'if'.  These nodes set ex_Cond to 0/1 or -1 depending on whether
  102.  *  they want to branch on true or false, and set ex_LabelT/ex_LabelF
  103.  *  appropriately.
  104.  */
  105.  
  106. void
  107. GenCondBranch(pexp)
  108. Exp **pexp;
  109. {
  110.     Exp *exp = *pexp;
  111.     Exp *e1;
  112.     Type *t1;
  113.  
  114.     if (GenPass == 0) {
  115.     e1 = exp->ex_ExpL;
  116.     e1->ex_Flags |= EF_COND;    /*    allow pass 1 opt of left */
  117.     CallLeft();
  118.     e1 = exp->ex_ExpL;
  119.  
  120.         t1 = e1->ex_Type;
  121.         /* If they didn't optimize the expression for us, we need to check   */
  122.         /* the type to ensure that it is acceptable for a conditional branch */
  123.         if (!(e1->ex_Flags & (EF_CONDACK|EF_RNU)))
  124.         {
  125.             if (t1 == NULL || t1->Id > TID_ARY) {
  126.         if (t1->Id != TID_BITFIELD)
  127.             yerror(e1->ex_LexIdx, EERROR_EXPECTED_INT_TYPE);
  128.             }
  129.             else if (t1->Size == 0) {
  130.         yerror(e1->ex_LexIdx, EERROR_UNEXPECTED_VOID_TYPE);
  131.             }
  132.         }
  133.     exp->ex_Type = &VoidType;
  134.     exp->ex_Flags |= e1->ex_Flags & EF_CALL;
  135.     if (t1 && t1->Id == TID_FLT)
  136.     {
  137.         exp->ex_Flags |= EF_CALL;
  138.         GenFlagCallMade();
  139.     }
  140.     } else {
  141.     e1 = exp->ex_ExpL;
  142.     e1->ex_Flags |= EF_COND;
  143.     if (exp->ex_Cond >= 0) {    /*  default case 0 == true  */
  144.         e1->ex_Cond = COND_T;
  145.         e1->ex_LabelT = exp->ex_LabelT;
  146.     } else {
  147.         e1->ex_Cond = COND_F;
  148.         e1->ex_LabelF = exp->ex_LabelF;
  149.     }
  150.  
  151.     CallLeft();
  152.  
  153.     exp->ex_Flags |= EF_CONDACK;
  154.     if (e1->ex_Flags & EF_CONDACK) {    /*  they branched for us    */
  155.         ;
  156.     } else {                /*    they didn't             */
  157.         if (e1->ex_Type->Id == TID_FLT)
  158.         asm_fptest(exp, &e1->ex_Stor);
  159.         else
  160.         asm_test(exp, &e1->ex_Stor);
  161.         FreeStorage(&e1->ex_Stor);
  162.         if (exp->ex_Cond >= 0)
  163.         asm_condbra(COND_NEQ, exp->ex_LabelT);
  164.         else
  165.         asm_condbra(COND_EQ, exp->ex_LabelF);
  166.     }
  167.     }
  168. }
  169.  
  170. /*
  171.  *  If exp1 && exp2
  172.  */
  173.  
  174. void
  175. GenAndAnd(pexp)
  176. Exp **pexp;
  177. {
  178.     Exp *exp = *pexp;
  179.     Exp *e1;
  180.     Exp *e2;
  181.  
  182.     if (GenPass == 0) {
  183.     CallLeft();
  184.     CallRight();
  185.     e1 = exp->ex_ExpL;
  186.     e2 = exp->ex_ExpR;
  187.  
  188.     if (e1->ex_Stor.st_Type == ST_IntConst) {
  189.         if (e1->ex_Stor.st_IntConst == 0) {
  190.         *pexp = e1;
  191.         e1->ex_Flags |= exp->ex_Flags & EF_RNU;
  192.         return;
  193.         }
  194.         if (e2->ex_Stor.st_Type == ST_IntConst) {
  195.         e1->ex_Stor.st_IntConst = (e1->ex_Stor.st_IntConst && e2->ex_Stor.st_IntConst);
  196.         *pexp = e1;
  197.         e1->ex_Flags |= exp->ex_Flags & EF_RNU;
  198.         return;
  199.         }
  200.     }
  201.     exp->ex_Type = &LongType;
  202.     exp->ex_Flags |= (e1->ex_Flags | e2->ex_Flags) & EF_CALL;
  203.  
  204.     if ((e1->ex_Type && e1->ex_Type->Id == TID_FLT) || (e2->ex_Type && e2->ex_Type->Id == TID_FLT)) {
  205.         exp->ex_Flags |= EF_CALL;
  206.         GenFlagCallMade();
  207.     }
  208.     } else {
  209.     if (exp->ex_Cond >= 0)
  210.         BoolLabels(exp, COND_F, COND_T);
  211.     else
  212.         BoolLabels(exp, COND_F, COND_F);
  213.  
  214.     CallLeft();
  215.     EnsureReturnStorageLeft();
  216.  
  217.     e1 = exp->ex_ExpL;
  218.  
  219.     if ((e1->ex_Flags & EF_CONDACK) == 0) {
  220.         if (e1->ex_Type->Id == TID_FLT)
  221.         asm_fptest(exp, &e1->ex_Stor);
  222.         else
  223.         asm_test(exp, &e1->ex_Stor);
  224.         FreeStorage(&e1->ex_Stor);
  225.         asm_condbra(COND_EQ, exp->ex_LabelF);
  226.     }
  227.  
  228.     CallRight();
  229.     e2 = exp->ex_ExpR;
  230.  
  231.     if ((e2->ex_Flags & EF_CONDACK) == 0) {
  232.         if (e2->ex_Type->Id == TID_FLT)
  233.         asm_fptest(exp, &e2->ex_Stor);
  234.         else
  235.         asm_test(exp, &e2->ex_Stor);
  236.         FreeStorage(&e2->ex_Stor);
  237.         if (exp->ex_Cond >= 0)
  238.         asm_condbra(COND_NEQ, exp->ex_LabelT);   /*  true, fall through false    */
  239.         else
  240.         asm_condbra(COND_EQ, exp->ex_LabelF);   /*  false, fall through true    */
  241.     }
  242.  
  243.     if (exp->ex_Flags & EF_COND) {      /*  parent wants us to cond.bra */
  244.         if (exp->ex_Cond > 0) {         /*  on true, we own the false label */
  245.         asm_label(exp->ex_LabelF);
  246.         } else {                /*    on false, we own the true label */
  247.         asm_label(exp->ex_LabelT);
  248.         }
  249.     } else {                /*    we own both labels  (fall through false)    */
  250.         if (exp->ex_Flags & EF_RNU) {
  251.         asm_label(exp->ex_LabelF);
  252.         asm_label(exp->ex_LabelT);
  253.         } else {
  254.         long skip = AllocLabel();
  255.  
  256.         CreateBinaryResultStorage(exp, 0);
  257.  
  258.         asm_label(exp->ex_LabelF);
  259.         asm_movei(exp, 0, &exp->ex_Stor);
  260.         asm_branch(skip);
  261.         asm_label(exp->ex_LabelT);
  262.         asm_movei(exp, 1, &exp->ex_Stor);
  263.         asm_label(skip);
  264.         }
  265.     }
  266.     }
  267. }
  268.  
  269. /*
  270.  *  ||
  271.  */
  272.  
  273. void
  274. GenOrOr(pexp)
  275. Exp **pexp;
  276. {
  277.     Exp *exp = *pexp;
  278.     Exp *e1;
  279.     Exp *e2;
  280.  
  281.     if (GenPass == 0) {
  282.     CallLeft();
  283.     CallRight();
  284.     e1 = exp->ex_ExpL;
  285.     e2 = exp->ex_ExpR;
  286.  
  287.     if (e1->ex_Stor.st_Type == ST_IntConst) {
  288.         if (e1->ex_Stor.st_IntConst != 0) {
  289.         *pexp = e1;
  290.         e1->ex_Flags |= exp->ex_Flags & EF_RNU;
  291.         return;
  292.         }
  293.         if (e2->ex_Stor.st_Type == ST_IntConst) {
  294.         e1->ex_Stor.st_IntConst = (e1->ex_Stor.st_IntConst || e2->ex_Stor.st_IntConst);
  295.         *pexp = e1;
  296.         e1->ex_Flags |= exp->ex_Flags & EF_RNU;
  297.         return;
  298.         }
  299.     }
  300.     exp->ex_Type = &LongType;
  301.     exp->ex_Flags |= (e1->ex_Flags | e2->ex_Flags) & EF_CALL;
  302.     if ((e1->ex_Type && e1->ex_Type->Id == TID_FLT) || (e2->ex_Type && e2->ex_Type->Id == TID_FLT)) {
  303.         exp->ex_Flags |= EF_CALL;
  304.         GenFlagCallMade();
  305.     }
  306.     } else {
  307.     if (exp->ex_Cond >= 0)
  308.         BoolLabels(exp, COND_T, COND_T);
  309.     else
  310.         BoolLabels(exp, COND_T, COND_F);
  311.  
  312.     CallLeft();
  313.     EnsureReturnStorageLeft();
  314.     e1 = exp->ex_ExpL;
  315.  
  316.     if ((e1->ex_Flags & EF_CONDACK) == 0) {
  317.         if (e1->ex_Type->Id == TID_FLT)
  318.         asm_fptest(exp, &e1->ex_Stor);
  319.         else
  320.         asm_test(exp, &e1->ex_Stor);
  321.         FreeStorage(&e1->ex_Stor);
  322.         asm_condbra(COND_NEQ, exp->ex_LabelT);
  323.     }
  324.  
  325.     CallRight();
  326.     e2 = exp->ex_ExpR;
  327.  
  328.     if ((e2->ex_Flags & EF_CONDACK) == 0) {
  329.         if (e2->ex_Type->Id == TID_FLT)
  330.         asm_fptest(exp, &e2->ex_Stor);
  331.         else
  332.         asm_test(exp, &e2->ex_Stor);
  333.         FreeStorage(&e2->ex_Stor);
  334.         if (exp->ex_Cond >= 0)
  335.         asm_condbra(COND_NEQ, exp->ex_LabelT);   /*  true, fall through false    */
  336.         else
  337.         asm_condbra(COND_EQ, exp->ex_LabelF);   /*  false, fall through true    */
  338.     }
  339.  
  340.     if (exp->ex_Flags & EF_COND) {      /*  parent wants us to cond.bra */
  341.         if (exp->ex_Cond > 0) {         /*  on true, we own the false label */
  342.         asm_label(exp->ex_LabelF);
  343.         } else {                /*    on false, we own the true label */
  344.         asm_label(exp->ex_LabelT);
  345.         }
  346.     } else {                /*    we own both labels  (fall through false)    */
  347.         if (exp->ex_Flags & EF_RNU) {
  348.         asm_label(exp->ex_LabelF);
  349.         asm_label(exp->ex_LabelT);
  350.         } else {
  351.         long skip = AllocLabel();
  352.  
  353.         CreateBinaryResultStorage(exp, 0);
  354.  
  355.         asm_label(exp->ex_LabelF);
  356.         asm_movei(exp, 0, &exp->ex_Stor);
  357.         asm_branch(skip);
  358.         asm_label(exp->ex_LabelT);
  359.         asm_movei(exp, 1, &exp->ex_Stor);
  360.         asm_label(skip);
  361.         }
  362.     }
  363.     }
  364. }
  365.  
  366. /*
  367.  *  Compare exp == exp
  368.  */
  369.  
  370. void
  371. GenBoolCompareSame(pexp)
  372. Exp **pexp;
  373. {
  374.     Exp *exp = *pexp;
  375.     Exp *e1;
  376.     Exp *e2;
  377.  
  378.     if (GenPass == 0) {
  379.     CallLeft();
  380.     CallRight();
  381.  
  382.     e1 = exp->ex_ExpL;
  383.     e2 = exp->ex_ExpR;
  384.  
  385.     exp->ex_Flags |= (e1->ex_Flags | e2->ex_Flags) & EF_CALL;
  386.  
  387.     /*
  388.      *  handle constant case
  389.      */
  390.  
  391.     if (e1->ex_Stor.st_Type == ST_IntConst && e2->ex_Stor.st_Type == ST_IntConst) {
  392.         if (exp->ex_Token == TokEqEq)
  393.         e1->ex_Stor.st_IntConst = (e1->ex_Stor.st_IntConst == e2->ex_Stor.st_IntConst);
  394.         else
  395.         e1->ex_Stor.st_IntConst = (e1->ex_Stor.st_IntConst != e2->ex_Stor.st_IntConst);
  396.         e1->ex_Type = &LongType;
  397.         *pexp = e1;
  398.         return;
  399.     }
  400.  
  401.     /*
  402.      *  optimize conditional.  If either side is 0 then remove
  403.      *  our rule if != 0, change our rule to '!exp' if == 0.  Only
  404.      *  works if EF_COND set in pass 1.
  405.      */
  406.  
  407.     if (exp->ex_Flags & EF_COND) {
  408.         if (e1->ex_Stor.st_Type == ST_IntConst && e1->ex_Stor.st_IntConst == 0) {
  409. #ifdef NOTDEF
  410.             if (e2->ex_Type->Size == 0)
  411.             yerror(e2->ex_LexIdx, EERROR_UNEXPECTED_VOID_TYPE);
  412. #endif
  413.  
  414.                 if (exp->ex_Token == TokEqEq) { /*  change to '!exp'    */
  415.             exp->ex_Func = GenNot;
  416.             exp->ex_ExpL = e2;
  417.                  exp->ex_Type = &LongType;
  418.         } else {            /*  change to just 'exp'*/
  419.             *pexp = e2;
  420.             e2->ex_Flags |= exp->ex_Flags & EF_RNU;
  421.         }
  422.         return;
  423.         } else if (e2->ex_Stor.st_Type == ST_IntConst && e2->ex_Stor.st_IntConst == 0) {
  424. #ifdef NOTDEF
  425.             if (e1->ex_Type->Size == 0)
  426.             yerror(e1->ex_LexIdx, EERROR_UNEXPECTED_VOID_TYPE);
  427. #endif
  428.         if (exp->ex_Token == TokEqEq) { /*  change to '!exp'    */
  429.             exp->ex_Func = GenNot;
  430.                  exp->ex_Type = &LongType;
  431.         } else {            /*  change to just 'exp'*/
  432.             *pexp = e1;
  433.             e1->ex_Flags |= exp->ex_Flags & EF_RNU;
  434.         }
  435.         return;
  436.         }
  437.     }
  438.     CompareRules(exp, 1);
  439.     e1 = exp->ex_ExpL;
  440.     e1 = exp->ex_ExpR;
  441.     exp->ex_Flags |= (e1->ex_Flags | e2->ex_Flags) & EF_CALL;
  442.     if (e1->ex_Type->Id == TID_FLT) {   /*  either e1 or e2     */
  443.         exp->ex_Flags |= EF_CALL;
  444.         GenFlagCallMade();
  445.     }
  446.     } else {
  447.     short cond = (exp->ex_Token == TokEqEq) ? COND_EQ : COND_NEQ;
  448.  
  449.     BoolLabels(exp, 0, 0);
  450.  
  451.     CallLeft();
  452.     EnsureReturnStorageLeft();
  453.     CallRight();
  454.     e1 = exp->ex_ExpL;
  455.     e2 = exp->ex_ExpR;
  456.  
  457.     if (exp->ex_Flags & EF_COND) {      /*  parent wants us to cond.bra */
  458.         if (e1->ex_Type->Id == TID_FLT)
  459.         asm_fpcmp(exp, &e1->ex_Stor, &e2->ex_Stor, &cond);
  460.         else
  461.         asm_cmp(exp, &e1->ex_Stor, &e2->ex_Stor, &cond);
  462.  
  463.         FreeStorage(&e1->ex_Stor);
  464.         FreeStorage(&e2->ex_Stor);
  465.  
  466.         if (exp->ex_Cond > 0) {         /*  on true, we own the false label */
  467.         asm_condbra(cond, exp->ex_LabelT);
  468.         asm_label(exp->ex_LabelF);
  469.         } else {                /*    on false, we own the true label */
  470.         asm_condbra(-cond, exp->ex_LabelF);
  471.         asm_label(exp->ex_LabelT);
  472.         }
  473.     } else {                /*    we own both labels  */
  474.         if (exp->ex_Flags & EF_RNU) {
  475.         FreeStorage(&e1->ex_Stor);
  476.         FreeStorage(&e2->ex_Stor);
  477.         yerror(exp->ex_LexIdx, EWARN_RESULT_NOT_USED);
  478.         } else {
  479.         CreateBinaryResultStorage(exp, 1);
  480.  
  481.         asm_cond_scc(exp, e1->ex_Type->Id, &e1->ex_Stor, &e2->ex_Stor, &cond, &exp->ex_Stor);
  482.         }
  483.     }
  484.     }
  485. }
  486.  
  487. void
  488. GenBoolCompare(pexp)
  489. Exp **pexp;
  490. {
  491.     Exp *exp = *pexp;
  492.     Exp *e1;
  493.     Exp *e2;
  494.     short cond;
  495.  
  496.     if (GenPass == 0) {
  497.     CallLeft();
  498.     CallRight();
  499.  
  500.     CompareRules(exp, 0);
  501.  
  502.     e1 = exp->ex_ExpL;
  503.     e2 = exp->ex_ExpR;
  504.  
  505.     exp->ex_Flags |= (e1->ex_Flags | e2->ex_Flags) & EF_CALL;
  506.     if (e1->ex_Type->Id == TID_FLT) {   /*  either e1 or e2 */
  507.         exp->ex_Flags |= EF_CALL;
  508.         GenFlagCallMade();
  509.     }
  510.  
  511.  
  512.     if (e1->ex_Stor.st_Type == ST_IntConst && e2->ex_Stor.st_Type == ST_IntConst) {
  513.         int result = 0;
  514.         long v1 = e1->ex_Stor.st_IntConst;
  515.         long v2 = e2->ex_Stor.st_IntConst;
  516.  
  517.         if (e1->ex_Type->Flags & TF_UNSIGNED) {
  518.         switch(exp->ex_Token) {
  519.         case TokLt:
  520.             result = (ulong)v1 < (ulong)v2;
  521.             break;
  522.         case TokLtEq:
  523.             result = (ulong)v1 <= (ulong)v2;
  524.             break;
  525.         case TokGt:
  526.             result = (ulong)v1 > (ulong)v2;
  527.             break;
  528.         case TokGtEq:
  529.             result = (ulong)v1 >= (ulong)v2;
  530.             break;
  531.         default:
  532.             Assert(0);
  533.         }
  534.         } else {
  535.         switch(exp->ex_Token) {
  536.         case TokLt:
  537.             result = v1 < v2;
  538.             break;
  539.         case TokLtEq:
  540.             result = v1 <= v2;
  541.             break;
  542.         case TokGt:
  543.             result = v1 > v2;
  544.             break;
  545.         case TokGtEq:
  546.             result = v1 >= v2;
  547.             break;
  548.         default:
  549.             Assert(0);
  550.         }
  551.         }
  552.         e1->ex_Type = &LongType;
  553.         e1->ex_Stor.st_IntConst = result;
  554.         *pexp = e1;
  555.         return;
  556.     }
  557.     exp->ex_Type = &LongType;
  558.     } else {
  559.     BoolLabels(exp, 0, 0);
  560.  
  561.     CallLeft();
  562.     EnsureReturnStorageLeft();
  563.     CallRight();
  564.  
  565.     e1 = exp->ex_ExpL;
  566.     e2 = exp->ex_ExpR;
  567.  
  568.     switch(exp->ex_Token) {
  569.         case TokLt:        cond = COND_LT;        break;
  570.         case TokLtEq:    cond = COND_LTEQ;    break;
  571.         case TokGt:        cond = COND_GT;        break;
  572.         case TokGtEq:    cond = COND_GTEQ;    break;
  573.         default:        Assert(0);
  574.     }
  575.     if (e1->ex_Type->Flags & TF_UNSIGNED) {
  576.         cond |= CF_UNS;
  577.     }
  578.  
  579.     if (exp->ex_Flags & EF_COND) {      /*  parent wants us to cond.bra */
  580.         if (e1->ex_Type->Id == TID_FLT)
  581.         asm_fpcmp(exp, &e1->ex_Stor, &e2->ex_Stor, &cond);     /*  if cmp reverses args it negates cond */
  582.         else
  583.         asm_cmp(exp, &e1->ex_Stor, &e2->ex_Stor, &cond);     /*  if cmp reverses args it negates cond */
  584.         FreeStorage(&e1->ex_Stor);
  585.         FreeStorage(&e2->ex_Stor);
  586.         if (exp->ex_Cond > 0) {         /*  on true, we own the false label */
  587.         asm_condbra(cond, exp->ex_LabelT);
  588.         asm_label(exp->ex_LabelF);
  589.         } else {                /*    on false, we own the true label */
  590.         asm_condbra(-cond, exp->ex_LabelF);
  591.         asm_label(exp->ex_LabelT);
  592.         }
  593.     } else {                /*    we own both labels  */
  594.         if (exp->ex_Flags & EF_RNU) {
  595.         FreeStorage(&e1->ex_Stor);
  596.         FreeStorage(&e2->ex_Stor);
  597.         yerror(exp->ex_LexIdx, EWARN_RESULT_NOT_USED);
  598.         } else {
  599.         CreateBinaryResultStorage(exp, 1);
  600.         asm_cond_scc(exp, e1->ex_Type->Id, &e1->ex_Stor, &e2->ex_Stor, &cond, &exp->ex_Stor);
  601.         }
  602.     }
  603.     return;
  604.     }
  605. }
  606.  
  607. void
  608. GenNot(pexp)
  609. Exp **pexp;
  610. {
  611.     Exp *exp = *pexp;
  612.     Exp *e1;
  613.  
  614.     if (GenPass == 0) {
  615.     CallLeft();
  616.     e1 = exp->ex_ExpL;
  617.  
  618.     if (e1->ex_Stor.st_Type == ST_IntConst) {
  619.         e1->ex_Stor.st_IntConst = !e1->ex_Stor.st_IntConst;
  620.         e1->ex_Type = &LongType;
  621.         *pexp = e1;
  622.     }
  623.  
  624.  
  625.         /* If they didn't optimize the expression for us, we need to check   */
  626.         /* the type to ensure that it is acceptable for a conditional branch */
  627.         if (!(e1->ex_Flags & (EF_CONDACK|EF_RNU)))
  628.         {
  629.         Type *t1;
  630.         t1 = e1->ex_Type;
  631.  
  632.             if (t1 == NULL || t1->Id > TID_ARY) {
  633.         if (t1->Id != TID_BITFIELD)
  634.             yerror(e1->ex_LexIdx, EERROR_EXPECTED_INT_TYPE);
  635.             }
  636.             else if (t1->Size == 0) {
  637.         yerror(e1->ex_LexIdx, EERROR_UNEXPECTED_VOID_TYPE);
  638.         }
  639.     }
  640.  
  641.  
  642.     exp->ex_Type = &LongType;
  643.     exp->ex_Flags |= e1->ex_Flags & EF_CALL;
  644.     if (e1->ex_Type && e1->ex_Type->Id == TID_FLT) {
  645.         exp->ex_Flags |= EF_CALL;
  646.         GenFlagCallMade();
  647.     }
  648.     } else {
  649.     e1 = exp->ex_ExpL;
  650.     if (exp->ex_Flags & EF_COND) {
  651.         exp->ex_Flags |= EF_CONDACK;
  652.  
  653.         /*
  654.          *    if parent wants true condition we request false condition
  655.          *    if parent wants false condition we request true condition
  656.          */
  657.  
  658.         if (exp->ex_Cond > 0) {
  659.         e1->ex_Flags |= EF_COND;
  660.         e1->ex_Cond = -1;
  661.         e1->ex_LabelF = exp->ex_LabelT;
  662.         } else {
  663.         e1->ex_Flags |= EF_COND;
  664.         e1->ex_Cond = 1;
  665.         e1->ex_LabelT = exp->ex_LabelF;
  666.         }
  667.     } else {
  668.         ;    /*  should we ask the lower routine to branch for us? */
  669.     }
  670.  
  671.     CallLeft();
  672.     e1 = exp->ex_ExpL;
  673.  
  674.     if (exp->ex_Flags & EF_COND) {
  675.         if (e1->ex_Flags & EF_CONDACK) {
  676.         ;                /*  nothing to do */
  677.         } else {
  678.         if (e1->ex_Type->Id == TID_FLT)
  679.             asm_fptest(exp, &e1->ex_Stor);
  680.         else
  681.             asm_test(exp, &e1->ex_Stor);
  682.         FreeStorage(&e1->ex_Stor);
  683.         if (exp->ex_Cond >= 0)
  684.             asm_condbra(COND_EQ, exp->ex_LabelT);
  685.         else
  686.             asm_condbra(COND_NEQ, exp->ex_LabelF);
  687.         }
  688.     } else {
  689.         if (exp->ex_Flags & EF_RNU) {
  690.         FreeStorage(&e1->ex_Stor);
  691.         yerror(exp->ex_LexIdx, EWARN_RESULT_NOT_USED);
  692.         } else {
  693.         CreateUnaryResultStorage(exp, 1);
  694.  
  695.         asm_test_scc(exp, e1->ex_Type->Id, &e1->ex_Stor, COND_EQ, &exp->ex_Stor);
  696.         }
  697.     }
  698.     return;
  699.     }
  700. }
  701.  
  702. /*
  703.  *        :
  704.  *           / \
  705.  *          ?   c
  706.  *         a b   e3
  707.  *        e1 e2
  708.  *  We are talking massive constant & branch optimization here
  709.  */
  710.  
  711. void
  712. GenColon(pexp)
  713. Exp **pexp;
  714. {
  715.     Exp *exp = *pexp;
  716.     Exp *e1;
  717.     Exp *e2;
  718.     Exp *e3;
  719.     long lmiddle;
  720.     long lend;
  721.  
  722.     Assert(exp->ex_ExpL->ex_Token == TokQuestion);
  723.     e1 = exp->ex_ExpL->ex_ExpL;
  724.     e2 = exp->ex_ExpL->ex_ExpR;
  725.     e3 = exp->ex_ExpR;
  726.  
  727.     if (GenPass == 0) {
  728.     (*e1->ex_Func)(&e1);
  729.     (*e2->ex_Func)(&e2);
  730.     (*e3->ex_Func)(&e3);
  731.  
  732.     exp->ex_Flags |= (e1->ex_Flags | e2->ex_Flags | e3->ex_Flags) & EF_CALL;
  733.     if (e1->ex_Type->Id == TID_FLT || e2->ex_Type->Id == TID_FLT || e3->ex_Type->Id == TID_FLT) {
  734.         exp->ex_Flags |= EF_CALL;
  735.         GenFlagCallMade();
  736.     }
  737.  
  738.     exp->ex_ExpL->ex_ExpL = e1;
  739.     exp->ex_ExpL->ex_ExpR = e2;
  740.     exp->ex_ExpR = e3;
  741.  
  742.     if (e1->ex_Stor.st_Type == ST_IntConst) {
  743.         if (e1->ex_Stor.st_IntConst) {
  744.         *pexp = e2;
  745.         e2->ex_Flags |= exp->ex_Flags & EF_RNU;
  746.         } else {
  747.         *pexp = e3;
  748.         e3->ex_Flags |= exp->ex_Flags & EF_RNU;
  749.         }
  750.         return;
  751.     }
  752.     InsertBranch(&e1, COND_F, 0);
  753.     /*
  754.      *  Temporarily supercede exp.    el, e3
  755.      */
  756.     if ((exp->ex_Flags & EF_RNU) == 0)
  757.     {
  758.         Exp *el = exp->ex_ExpL;
  759.  
  760.         exp->ex_ExpL = e2;
  761.         MatchRules(exp);      /*  e2,e3 no longer valid */
  762.         el->ex_ExpR = exp->ex_ExpL;
  763.         exp->ex_ExpL = el;
  764.     }
  765.     exp->ex_ExpL->ex_ExpL = e1;
  766.     } else {
  767.     short cbr;
  768.  
  769.     lmiddle = AllocLabel();
  770.     lend    = AllocLabel();
  771.  
  772.     if (exp->ex_Cond >= 0)      /*  branch on true      */
  773.         exp->ex_LabelF = lend;  /*    we own false label  */
  774.     else                /*    branch on false...  */
  775.         exp->ex_LabelT = lend;  /*    we own true label   */
  776.  
  777.     e1->ex_LabelF = lmiddle;
  778.  
  779.     /*
  780.      *  an EF_COND on exp really means an EF_COND for subexps e2 and e3,
  781.      *  NOT e1.  If one of e2 or e3 cannot handle the condition we must
  782.      *  put in a test-branch ourselves.
  783.      */
  784.  
  785.     if (exp->ex_Flags & EF_COND) {
  786.         exp->ex_Flags |= EF_CONDACK;
  787.         e2->ex_Flags |= EF_COND;
  788.         e2->ex_Cond = exp->ex_Cond;
  789.         e2->ex_LabelT = exp->ex_LabelT;
  790.         e2->ex_LabelF = exp->ex_LabelF;
  791.  
  792.         e3->ex_Flags |= EF_COND;
  793.         e3->ex_Cond = exp->ex_Cond;
  794.         e3->ex_LabelT = exp->ex_LabelT;
  795.         e3->ex_LabelF = exp->ex_LabelF;
  796.     } else
  797.     if (exp->ex_Flags & EF_RNU) {
  798.         e2->ex_Flags |= EF_RNU;
  799.         e3->ex_Flags |= EF_RNU;
  800.     }
  801.  
  802.     /*
  803.      *  Use a trick to allocate the result storage.  Since the storage
  804.      *  is not used until the end we allocate and free it here (otherwise
  805.      *  the temporary register is unusable inside the possibly complex
  806.      *  expression)
  807.      */
  808.  
  809.         if (exp->ex_Type == NULL)
  810.             exp->ex_Type = &VoidType;
  811.  
  812.     cbr = CreateBinaryResultStorage(exp, 0);
  813.     if (cbr == 2)
  814.         FreeStorage(&exp->ex_Stor);
  815.  
  816.     /*
  817.      *  a not a constant.  a branches to either e2 or e3
  818.      */
  819.  
  820.     (*e1->ex_Func)(&e1);   /*  branches to e2 or e3    */
  821.  
  822.     (*e2->ex_Func)(&e2);
  823.     if (cbr == 2)
  824.         ReuseStorage(&exp->ex_Stor, &exp->ex_Stor);
  825.     TerminateCondition(e2, exp);
  826.     asm_branch(lend);
  827.  
  828.     asm_label(lmiddle);
  829.  
  830.     if (cbr == 2)
  831.         FreeStorage(&exp ->ex_Stor);
  832.     (*e3->ex_Func)(&e3);
  833.     if (cbr == 2)
  834.         ReuseStorage(&exp->ex_Stor, &exp->ex_Stor);
  835.  
  836.     TerminateCondition(e3, exp);
  837.  
  838.     asm_label(lend);
  839.     }
  840. }
  841.  
  842. Local void
  843. TerminateCondition(sub, exp)
  844. Exp *sub;
  845. Exp *exp;
  846. {
  847.     switch(exp->ex_Flags & (EF_RNU|EF_CONDACK)) {
  848.     case 0:            /*  normal return value */
  849.     FreeStorage(&sub->ex_Stor);
  850.     asm_move_cast(exp, &sub->ex_Stor, &exp->ex_Stor);
  851.     break;
  852.     case EF_RNU:         /*  no return value or condition     */
  853.     if ((sub->ex_Flags & EF_RNU) == 0) {
  854.         FreeStorage(&sub->ex_Stor);
  855.     }
  856.     break;
  857.     case EF_CONDACK:        /*  conditional branch        */
  858.     if ((sub->ex_Flags & EF_CONDACK) == 0) {
  859.         if (sub->ex_Type->Id == TID_INT && sub->ex_Stor.st_Type == ST_IntConst) {
  860.         if (exp->ex_Cond >= 0 && sub->ex_Stor.st_IntConst)
  861.             asm_branch(exp->ex_LabelT);
  862.         else if (exp->ex_Cond < 0 && sub->ex_Stor.st_IntConst == 0)
  863.             asm_branch(exp->ex_LabelF);
  864.         } else {
  865.         if (sub->ex_Type->Id == TID_FLT)
  866.             asm_fptest(exp, &sub->ex_Stor);
  867.         else
  868.             asm_test(exp, &sub->ex_Stor);
  869.         FreeStorage(&sub->ex_Stor);
  870.         if (exp->ex_Cond >= 0)      /*  branch on true  */
  871.             asm_condbra(COND_NEQ, exp->ex_LabelT);
  872.         else                /*    branch on false */
  873.             asm_condbra(COND_EQ, exp->ex_LabelF);
  874.         }
  875.     }
  876.     break;
  877.     case EF_RNU|EF_CONDACK:
  878.     Assert(0);
  879.     }
  880. }
  881.  
  882. void
  883. GenQuestion(pexp)
  884. Exp **pexp;
  885. {
  886.     Assert(0);
  887. }
  888.  
  889.